package com.whfp.coky.utils

import android.util.Base64
import android.util.Log
import com.hjq.demo.action.ToastAction
import java.io.UnsupportedEncodingException
import java.security.GeneralSecurityException
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec

/**
 * AES加密解密工具类
 */
object AESUtils :ToastAction{
    private const val AES_MODE = "AES/CBC/PKCS7Padding"
    private const val CHARSET = "UTF-8"
    private const val CIPHER = "AES"
    private const val HASH_ALGORITHM = "SHA-256"
    private val IV_BYTES = byteArrayOf(
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00,
        0x00
    )

    //超级管理员密码明文(将用户输入的密码（秘钥）解密超级管理员密码加密后的密文，得到的如果是超级管理员密码明文则判定为正确)
    private const val passwordText = "臻稀生物"

    //超级管理员密码加密后的密文（由超级管理员密码明文通过秘钥 zx@123698745 加密而得来，此秘钥即为用户的要输入的管理员密码）
    private const val passwordCipherText = "vMNNiwIhfpLpjhw7n35JPA=="

    //====================================================秘钥区=============================================================
    //用于测试加密功能的秘钥
    private const val test_key = "zx@123698745"
    //====================================================秘钥区=============================================================
    /**
     * Generates SHA256 hash of the password which is used as key
     *
     * @param password used to generated key
     * @return SHA256 of the password
     */
    @Throws(NoSuchAlgorithmException::class, UnsupportedEncodingException::class)
    private fun generateKey(password: String): SecretKeySpec {
        val digest = MessageDigest.getInstance(HASH_ALGORITHM)
        val bytes = password.toByteArray(charset(CHARSET))
        digest.update(bytes, 0, bytes.size)
        val key = digest.digest()
        return SecretKeySpec(key, CIPHER)
    }

    /**
     * Encrypt and encode message using 256-bit AES with key generated from password.
     *
     * @param password used to generated key
     * @param message  the thing you want to encrypt assumed String UTF-8
     * @return Base64 encoded CipherText
     * @throws GeneralSecurityException if problems occur during encryption
     */
    @Throws(GeneralSecurityException::class)
    fun encrypt(password: String, message: String): String {
        return try {
            val key = generateKey(password)
            val cipherText = encrypt(key, IV_BYTES, message.toByteArray(charset(CHARSET)))
            //NO_WRAP is important as was getting \n at the end
            Base64.encodeToString(cipherText, Base64.NO_WRAP)
        } catch (e: UnsupportedEncodingException) {
            throw GeneralSecurityException(e)
        }
    }

    /**
     * More flexible AES encrypt that doesn't encode
     *
     * @param key     AES key typically 128, 192 or 256 bit
     * @param iv      Initiation Vector
     * @param message in bytes (assumed it's already been decoded)
     * @return Encrypted cipher text (not encoded)
     * @throws GeneralSecurityException if something goes wrong during encryption
     */
    @Throws(GeneralSecurityException::class)
    fun encrypt(key: SecretKeySpec?, iv: ByteArray?, message: ByteArray?): ByteArray {
        val cipher = Cipher.getInstance(AES_MODE)
        val ivSpec = IvParameterSpec(iv)
        cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec)
        return cipher.doFinal(message)
    }

    /**
     * Decrypt and decode ciphertext using 256-bit AES with key generated from password
     *
     * @param password                used to generated key
     * @param base64EncodedCipherText the encrpyted message encoded with base64
     * @return message in Plain text (String UTF-8)
     * @throws GeneralSecurityException if there's an issue decrypting
     */
    @Throws(GeneralSecurityException::class)
    fun decrypt(password: String, base64EncodedCipherText: String?): String {
        return try {
            val key = generateKey(password)
            val decodedCipherText = Base64.decode(base64EncodedCipherText, Base64.NO_WRAP)
            val decryptedBytes = decrypt(key, IV_BYTES, decodedCipherText)
            String(decryptedBytes, charset(CHARSET))
        } catch (e: UnsupportedEncodingException) {
            throw GeneralSecurityException(e)
        }
    }

    /**
     * More flexible AES decrypt that doesn't encode
     *
     * @param key               AES key typically 128, 192 or 256 bit
     * @param iv                Initiation Vector
     * @param decodedCipherText in bytes (assumed it's already been decoded)
     * @return Decrypted message cipher text (not encoded)
     * @throws GeneralSecurityException if something goes wrong during encryption
     */
    @Throws(GeneralSecurityException::class)
    fun decrypt(key: SecretKeySpec?, iv: ByteArray?, decodedCipherText: ByteArray?): ByteArray {
        val cipher = Cipher.getInstance(AES_MODE)
        val ivSpec = IvParameterSpec(iv)
        cipher.init(Cipher.DECRYPT_MODE, key, ivSpec)
        return cipher.doFinal(decodedCipherText)
    }

    /**
     * 测试加密
     *
     * @param str
     * @return
     */
    @Throws(GeneralSecurityException::class)
    fun encryptTest(str: String): String {
        val s = encrypt(test_key, str)
        Log.i("加密：", s)
        return s
    }

    /**
     * 测试解密
     *
     * @param str
     * @return
     */
    @Throws(GeneralSecurityException::class)
    fun decryptTest(str: String?): String {
        val s = decrypt(test_key, str)
        Log.i("解密：", s)
        return s
    }

    /**
     * 判断超级管理员密码是否正确
     *
     * @param key 超级管理员密码
     * @return
     */
    fun decryptAdministratorPassword(key: String): Boolean {
        return try {
            decrypt(key, passwordCipherText)== passwordText
        } catch (e: GeneralSecurityException) {
            e.printStackTrace()
            LogUtil.e("解密出粗：$e")
            false
        }
    }

    /**
     * 打印机【ZXLDYJ-01】的二维码解密
     *
     * @param str 扫描打印机上的二维码得来的密文
     * @return 打印机的蓝牙mac地址
     */
    fun decryptDeviceMacByZXLDYJ_01(str: String): String? {
        //第一步：判断是否是“@@”分割的字符串
        if (str.isNullOrEmpty() || !str.contains("@@")) {
            toast("二维码不合规")
            return null
        }
        //第二步：尝试解密通过“@@”截取出来的前段密文
        val s = try {
            val ycl = str.substring(0, str.indexOf("@@"))
            LogUtil.i("截取出来的预处理密文：$ycl")
            decryptDeviceMac(ycl)
        } catch (e: Exception) {
            e.printStackTrace()
            LogUtil.e("打印机【ZXLDYJ-01】二维码解密出错：${e.toString()}")
            toast("二维码不合规")
            return null
        }
        //第三步：判断解密出来的明文长度是否合规
        if (s.isNullOrEmpty() || s.length != 26) {
            LogUtil.i("这里66666：$s")
            LogUtil.e("打印机【ZXLDYJ-01】二维码解密出的明文长度不合规")
            toast("二维码不合规")
            return null
        }
        //第四步：判断是否是属于破冰2的二维码(判断方法为比对明文前9为的字符串是否是“ZXLDYJ-01”)
        val xh = s.substring(0, 9)
        val mac = s.substring(9, s.length)
        LogUtil.i("打印机：" + s + "型号：" + xh + "地址：" + mac)
        if (xh != "ZXLDYJ-01") {
            LogUtil.e("不是打印机【ZXLDYJ-01】的型号")
            toast("二维码不合规")
            return null
        }
        //第五步：判断是否是正确的MAC地址
        if (!isMac(mac)) {
            LogUtil.e("MAC地址不正确")
            toast("二维码不合规")
            return null
        }
        return mac
    }

    /**
     * 加密设备MAC地址
     *
     * @param str
     * @return
     */
    @Throws(GeneralSecurityException::class)
    fun encryptDeviceMac(str: String): String {
        val s = encrypt(device_key, str)
        Log.i("加密：", str)
        return s
    }

    /**
     * 解密设备MAC地址
     *
     * @param str
     * @return
     */
    @Throws(GeneralSecurityException::class)
    fun decryptDeviceMac(str: String?): String {
        val s = decrypt(device_key, str)
        Log.i("解密：", str!!)
        return s
    }

    //解密设备MAC地址的秘钥
    private const val device_key = "zenith-bio"


    /**
     * 判断字符串是否是个mac地址
     *
     * @param str 要判断的字符串
     * @return 判断结果
     */
    // val zz =Regex("[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]:[0-9A-F][0-9A-F]")
    fun isMac(str: String?): Boolean {
        if (str.isNullOrEmpty()){
            return false
        }
        val zz =Regex("([A-Fa-f0-9]{2}:){5}[A-Fa-f0-9]{2}")
        return str.matches(zz)
    }

}